package bjtu.tjj.simpledy.service.impl;

import bjtu.tjj.simpledy.common.ResultCode;
import bjtu.tjj.simpledy.common.keys.RedisKey;
import bjtu.tjj.simpledy.dto.*;
import bjtu.tjj.simpledy.exception.CommonException;
import bjtu.tjj.simpledy.mapper.UserMapper;
import bjtu.tjj.simpledy.po.UserPO;
import bjtu.tjj.simpledy.service.UserService;
import bjtu.tjj.simpledy.utils.FileUtils;
import bjtu.tjj.simpledy.utils.SHA256Utils;
import bjtu.tjj.simpledy.utils.ThreadLocalUtils;
import bjtu.tjj.simpledy.utils.UUIDUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.util.List;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    private final RedisTemplate<String, Object> redisTemplate;
    private final UserMapper userMapper;
    @Value("${auth.token-expire-days}")
    private int tokenExpireDays;

    private String encrypt(String password) {
        return SHA256Utils.encode("tjjnb666%stjjnb666".formatted(password));
    }

    @Override
    public void register(NameAndPwdDTO nameAndPwdDTO) {
        UserPO userPO = new UserPO();
        userPO.setId(UUIDUtils.next());
        userPO.setUsername(nameAndPwdDTO.getUsername());
        userPO.setPassword(encrypt(nameAndPwdDTO.getPassword()));
        int res = userMapper.insert(userPO);
        if (res == 0) {
            throw new CommonException(ResultCode.USERNAME_EXIST);
        }
    }

    @Override
    public String login(NameAndPwdDTO nameAndPwdDTO) {
        UserPO userPO = userMapper.findByUsername(nameAndPwdDTO.getUsername());
        if (userPO == null) {
            throw new CommonException(ResultCode.USERNAME_NOT_EXIST);
        }
        if (!userPO.getPassword().equals(encrypt(nameAndPwdDTO.getPassword()))) {
            throw new CommonException(ResultCode.INCORRECT_PWD);
        }
        Long userId = userPO.getId();
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        String uid2TokenKey = RedisKey.UID_TO_TOKEN + userId;
        String oldToken = (String) ops.get(uid2TokenKey);
        if (oldToken != null) {
            redisTemplate.delete(RedisKey.TOKEN_TO_UID + oldToken);
        }
        String token = UUIDUtils.nextStr(9);
        ops.set(RedisKey.TOKEN_TO_UID + token, userId, Duration.ofDays(tokenExpireDays));
        ops.set(uid2TokenKey, token, Duration.ofDays(tokenExpireDays));
        return token;
    }

    @Override
    public void logout() {
        TokenAndUidDTO dto = ThreadLocalUtils.get();
        String[] keys = {
                RedisKey.TOKEN_TO_UID + dto.token,
                RedisKey.UID_TO_TOKEN + dto.userId
        };
        redisTemplate.delete(List.of(keys));
    }

    @Override
    public void destroy(PwdDTO pwdDTO) {
        IdAndPwdDTO idAndPwdDTO = new IdAndPwdDTO();
        idAndPwdDTO.setId(ThreadLocalUtils.getUserId());
        idAndPwdDTO.setPassword(encrypt(pwdDTO.getPassword()));
        int res = userMapper.destroy(idAndPwdDTO);
        if (res == 0) {
            throw new CommonException(ResultCode.INCORRECT_PWD);
        }
        logout();
    }

    @Override
    public String updateAvatar(MultipartFile avatar) {
        // 检查文件后缀
        String suffix;
        if ((suffix = FileUtils.getSuffix(avatar)) == null || !FileUtils.isImage(suffix)) {
            throw new CommonException(ResultCode.ILLEGAL_VIDEO_SUFFIX);
        }
        String avatarFilename;
        try {
            File file = FileUtils.saveFile(avatar.getBytes(), suffix);
            avatarFilename = file.getName();
        } catch (IOException e) {
            throw new CommonException(ResultCode.AVATAR_UPLOAD_FILED);
        }
        int res = userMapper.updateAvatar(ThreadLocalUtils.getUserId(), avatarFilename);
        if (res == 0) {
            throw new CommonException(ResultCode.AVATAR_UPLOAD_FILED);
        }
        return avatarFilename;
    }

    @Override
    public UserDTO getSelf() {
        long id = ThreadLocalUtils.getUserId();
        UserPO userPO = userMapper.findById(id);
        if (userPO == null) {
            throw new CommonException(ResultCode.USER_NOT_EXIST);
        }
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(userPO, userDTO);
        return userDTO;
    }
}




